/* 
*  Copyright (C) 2009-2010 WCG Project
*
*  This program is free software; you can redistribute it and/or modify it
*  under the terms of the GNU General Public License as published by the
*  Free Software Foundation; either version 2 of the License, or (at
*  your option) any later version.
*
*  This program is distributed in the hope that it will be useful, but
*  WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
*  General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software Foundation,
*  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*  In addition, as a special exception, the author gives permission to
*  link the code of this program with the Half-Life Game Engine ("HL
*  Engine") and Modified Game Libraries ("MODs") developed by Valve,
*  L.L.C ("Valve"). You must obey the GNU General Public License in all
*  respects for all of the code used other than the HL Engine and MODs
*  from Valve. If you modify this file, you may extend this exception
*  to your version of the file, but you are not obligated to do so. If
*  you do not wish to do so, delete this exception statement from your
*  version.
*/



#define CHAINLIGHTNING_DAMAGE			50		// Initial ultimate damage
#define CHAINLIGHTNING_LINEWIDTH		80		// Width of the lightning sprite
#define CHAINLIGHTNING_MAXDISTANCE		1500.0	// Max distance between chainlightning targets
#define CRITICAL_STRIKE_CHANCE			0.10	// 10% chance of Critical Strike working

#define CHAINHEAL_LINEWIDTH				80
#define CHAINHEAL_MAXDISTANCE			1500.0	// Max distance between chainheal targets


new const Float:p_critical[5]			= {0.10, 0.20, 0.30, 0.40, 0.50}		// Critical Strike
new const Float:p_imp_critical[5]		= {0.02, 0.04, 0.06, 0.08, 0.10}		// Improved Critical Strike
new const Float:p_grenade[5]			= {1.30, 1.50, 1.70, 1.90, 2.10}		// Critical Grenade
new const p_chainheal[10]				= {32, 34, 36, 38, 40, 42, 44, 46, 48, 50}
new const p_chainheal_manacost[10]		= {20, 21, 22, 23, 24, 25, 26, 27, 28, 30}


SHAMAN_InitSkills()
{
	SM_InitSkill( SKILL_CRITICALSTRIKE, CLASS_SHAMAN, SKILL_TYPE_TRAINABLE, sizeof(p_critical) )
	SM_InitSkill( SKILL_IMPROVEDCRITICALSTRIKE, CLASS_SHAMAN, SKILL_TYPE_TRAINABLE, sizeof(p_imp_critical), 10, _, SKILL_CRITICALSTRIKE )
	SM_InitSkill( SKILL_CRITICALGRENADE, CLASS_SHAMAN, SKILL_TYPE_TRAINABLE, sizeof(p_grenade) )
//	SM_InitSkill( SKILL_REINCARNATION, CLASS_SHAMAN, SKILL_TYPE_TRAINABLE, sizeof(p_ankh) )
	SM_InitSkill( ABILITY_CHAINHEAL, CLASS_SHAMAN, SKILL_TYPE_ABILITY, sizeof(p_chainheal), 20, 10 )
	SM_InitSkill( ULTIMATE_CHAINLIGHTNING, CLASS_SHAMAN, SKILL_TYPE_ULTIMATE, 1, 10, 15 )
}


//------------------------------------
// SHAMAN_TriggerAbility
//
//------------------------------------
SHAMAN_TriggerAbility( id, iSkillID )
{
	if( iSkillID == ABILITY_CHAINHEAL )
	{
		new iSkillLevel = SM_GetSkillLevel( id, ABILITY_CHAINHEAL )

		new param[2]
		param[0] = id
		param[1] = iSkillLevel
		PLAYER_CastSpell( id, ABILITY_CHAINHEAL, CAST_NORMAL, "_SPELL_ChainHeal", param, 2 )
	}
}



//------------------------------------
// SHAMAN_TriggerUltimate
//
//------------------------------------
SHAMAN_TriggerUltimate( id, iSkillID )
{
	if( iSkillID == ULTIMATE_CHAINLIGHTNING )
	{
		PLAYER_CastSpell( id, ULTIMATE_CHAINLIGHTNING, CAST_SEARCH, "_SPELL_ChainLightning", _, _, CAST_SEARCH_OPPOSITE_TEAM )
	}
}




//------------------------------------
// SHAMAN_SkillsOffensive
//
//------------------------------------
public SHAMAN_SkillsOffensive( iAttacker, iVictim, iWeapon, &iDamage, iDamageType )
{
	static iSkillLevel

	// Critical Strike
	iSkillLevel = SM_GetSkillLevel( iAttacker, SKILL_CRITICALSTRIKE )
	if( iSkillLevel > 0 )
	{
		SHAMAN_CriticalStrike( iSkillLevel, iAttacker, iVictim, iDamage, iDamageType )
	}
}





//--------------------------------------------------------------------------------------------------------------------------
// Critical Strike


//------------------------------------
// SHAMAN_CriticalStrike
//
//------------------------------------
public SHAMAN_CriticalStrike( iSkillLevel, iAttacker, iVictim, &iDamage, iDamageType )
{
	if( !(iDamageType & DMG_BULLET) )
		return

	new Float:fChance = CRITICAL_STRIKE_CHANCE

	new iImpSkillLevel = SM_GetSkillLevel( iAttacker, SKILL_IMPROVEDCRITICALSTRIKE )

	if( iImpSkillLevel > 0 )
		fChance += p_imp_critical[iImpSkillLevel-1]

	if( random_float( 0.0, 1.0 ) <= fChance )
	{
		new iBonusDamage = floatround( float( iDamage ) * p_critical[iSkillLevel-1] )
		
		iDamage += iBonusDamage

		new iBrightness = min( 2*iBonusDamage, 150 )

		// Make the user glow
		SHARED_Glow( iVictim, COLOR_RGB( iBrightness, 0, 0 ) )
		EFFECT_ScreenFade( iVictim, 0.25, 0.2, COLOR_RGBA(255, 0, 0, iBrightness) )
		EFFECT_ScreenFade( iAttacker, 0.25, 0.2, COLOR_RGBA(255, 0, 0, iBrightness) )
	}
}


//--------------------------------------------------------------------------------------------------------------------------
// ChainLightning


//------------------------------------
// _SPELL_ChainLightning
//
// PLAYER_CastSpell callback
//		param[0] = Caster ID
//		param[1] = Victim ID
//		param[2] = ID of skill used for the search
//		param[3] = ID of target team
//		param[4] = Flags used by PLAYER_CastSpell
//------------------------------------
public _SPELL_ChainLightning( const param[] )
{
	new id			= param[0]
	new iTarget		= param[1]
	new iTargetTeam	= param[3]

	if( !PLAYER_CheckMagicHit( id, iTarget ) )
	{
		client_print( id, print_chat, "Your Chain Lightning was resisted by %s.", PlayerInfo[iTarget][PI_PlayerName] )
		client_print( iTarget, print_chat, "You resisted %s's Chain Lightning.", PlayerInfo[id][PI_PlayerName] )
		client_cmd( id, "spk %s", g_szSounds[SOUND_DISPELL] )
		return
	}

	// Display the lightning effect
	SHAMAN_ULT_ChainEffect( id, iTarget, id, CHAINLIGHTNING_LINEWIDTH, CHAINLIGHTNING_DAMAGE )

	// Now we need to search for the next "jump"
	new args[8]
	args[0] = CHAINLIGHTNING_DAMAGE
	args[1] = CHAINLIGHTNING_LINEWIDTH
	args[2] = id
	args[3] = 2
	args[4] = 0
	args[5] = 0
	args[6] = iTarget
	args[7] = iTargetTeam
	set_task( 0.25, "_SPELL_ChainLightningNext", TASK_EFFECT, args, 8 )
}



//------------------------------------
// SHAMAN_ULT_ChainEffect
//
//------------------------------------
public SHAMAN_ULT_ChainEffect( iCaster, iTarget, iPreviousTarget, iLineWidth, iDamage )
{
	// Damage the user
	PLAYER_MagicDamage( iTarget, iCaster, iDamage, CSW_LIGHTNING, DMG_RADIATION )
	
	// Create the lightning
	Create_TE_BEAMENTS( iPreviousTarget, iTarget, g_spr_lgtning, 0, 15, 10, iLineWidth, 10, 255, 255, 255, 255, 0 )
	
	// Get the target's origin
	new vOrigin[3]
	get_user_origin( iTarget, vOrigin )
	
	// Create an elight on the target
	Create_TE_ELIGHT( iTarget, vOrigin, 100, 255, 255, 255, 10, 0 )

	// Play the lightning sound
	emit_sound( iPreviousTarget, CHAN_STATIC, g_szSounds[SOUND_LIGHTNING], VOL_NORM, ATTN_NORM, 0, PITCH_NORM )
}




//------------------------------------
// _SPELL_ChainLightningNext
//
// Called on subsequent ultimate calls ( i.e. lightninghitnext )
//------------------------------------
public _SPELL_ChainLightningNext( param[] )
{
	static iPrevTargets[3], hTrace
	static Float:vOrigin[3], Float:vNextTargetOrigin[3], Float:view_ofs[3]

	new iDamage		= param[0]
	new iLineWidth	= param[1]
	new iCaster		= param[2]
	new iJump		= param[3]
	iPrevTargets[0]	= param[4]
	iPrevTargets[1]	= param[5]
	iPrevTargets[2]	= param[6]
	new iTargetTeam = param[7]

	if( !is_user_alive(iPrevTargets[iJump]) )
		return

	pev( iPrevTargets[iJump], pev_origin, vOrigin )
	pev( iPrevTargets[iJump], pev_view_ofs, view_ofs )
	xs_vec_add( vOrigin, view_ofs, vOrigin )

	new iBestTarget, Float:fDistance, Float:fBestDistance, Float:fFraction


	
	new iNextTarget
	
	for( new i = 0 ; i < g_NumTeamPlayers[iTargetTeam] ; i++ )
	{
		iNextTarget = g_SortedTeams[iTargetTeam][i]

		if( !is_user_alive(iNextTarget) )
			continue

		else if( iNextTarget == iPrevTargets[0] || iNextTarget == iPrevTargets[1] || iNextTarget == iPrevTargets[2] )
			continue

		pev( iNextTarget, pev_origin, vNextTargetOrigin )

		fDistance = get_distance_f( vOrigin, vNextTargetOrigin )
		if( fDistance > CHAINLIGHTNING_MAXDISTANCE )
			continue

		pev( iNextTarget, pev_view_ofs, view_ofs )
		xs_vec_add( vNextTargetOrigin, view_ofs, vNextTargetOrigin )

		engfunc( EngFunc_TraceLine, vOrigin, vNextTargetOrigin, IGNORE_MONSTERS|IGNORE_GLASS, FM_NULLENT, hTrace )
		get_tr2( hTrace, TR_flFraction, fFraction )

		if( fFraction < 0.9 )
			continue

		if( !PLAYER_CheckMagicHit( iCaster, iNextTarget ) )
		{
			client_print( iNextTarget, print_chat, "You resisted %s's Chain Lightning.", PlayerInfo[iCaster][PI_PlayerName] )
			continue
		}
		
		if( fDistance < fBestDistance || fBestDistance == 0.0 )
		{
			fBestDistance = fDistance
			iBestTarget = iNextTarget
		}
	}

	if( !iBestTarget )
		return

	iDamage = floatround( float(iDamage) * 0.70 )
	iLineWidth = floatround( float(iLineWidth) * 0.70 )

	SHAMAN_ULT_ChainEffect( iCaster, iBestTarget, iPrevTargets[iJump], iLineWidth, iDamage )

	if( --iJump < 0 )
		return
	
	iPrevTargets[iJump] = iBestTarget

	param[0] = iDamage
	param[1] = iLineWidth
	param[3] = iJump
	param[4] = iPrevTargets[0]
	param[5] = iPrevTargets[1]
	param[6] = iPrevTargets[2]
	set_task( 0.25, "_SPELL_ChainLightningNext", TASK_EFFECT, param, 8 )
}


//--------------------------------------------------------------------------------------------------------------------------
// Chain Heal


public _SPELL_ChainHeal( const param[] )
{
	new id			= param[0]
	new iSkillLevel	= param[1]
	new iHealth 	= p_chainheal[iSkillLevel-1]

	if( !is_user_alive( id ) )
		return

	Ability_ClearIcons( id )

	static Float:vOrigin[3], Float:view_ofs[3], vPos[3]
	get_user_origin( id, vPos )

	PLAYER_Heal( id, iHealth )
	Create_TE_ELIGHT( id, vPos, 100, 128, 255, 0, 10, 0 )
	emit_sound( id, CHAN_STATIC, g_szSounds[SOUND_HEAL_LOW_BASE], 0.5, ATTN_NORM, 0, PITCH_NORM )

	pev( id, pev_origin, vOrigin )
	pev( id, pev_view_ofs, view_ofs )

	new args[14]
	args[0] 	= iHealth
	args[1] 	= CHAINHEAL_LINEWIDTH
	args[2] 	= id
	args[3] 	= 3
	args[4] 	= 0
	args[5] 	= 0
	args[6] 	= 0
	args[7] 	= id
	args[8]		= floatround( vOrigin[0] )
	args[9]		= floatround( vOrigin[1] )
	args[10]	= floatround( vOrigin[2] )
	args[11]	= floatround( view_ofs[0] )
	args[12]	= floatround( view_ofs[1] )
	args[13]	= floatround( view_ofs[2] )
	_SPELL_ChainHealNext(args)
}



public _SPELL_ChainHealNext( param[] )
{
	static iPrevTargets[4], Float:vPrevTargetOrigin[3], Float:vPrevViewOfs[3], Float:vTargetOrigin[3], Float:view_ofs[3], Float:vTraceStart[3]

	new iTargetID, Float:fTargetHealth, hTrace, Float:fFraction

	new iHealth		= param[0]
	new iLineWidth	= param[1]
	new iCaster		= param[2]
	new iJump		= param[3]
	iPrevTargets[0]	= param[4]
	iPrevTargets[1]	= param[5]
	iPrevTargets[2]	= param[6]
	iPrevTargets[3]	= param[7]
	vPrevTargetOrigin[0] = float( param[8] )
	vPrevTargetOrigin[1] = float( param[9] )
	vPrevTargetOrigin[2] = float( param[10] )
	vPrevViewOfs[0] = float( param[11] )
	vPrevViewOfs[1] = float( param[12] )
	vPrevViewOfs[2] = float( param[13] )

	if( !is_user_alive( iPrevTargets[iJump] ) )
		return

	xs_vec_add( vPrevTargetOrigin, vPrevViewOfs, vTraceStart )

	new iTargetTeamID = PlayerInfo[iCaster][PI_TeamID]

	new iBestTarget = 0
	new Float:fBestTargetHealth = 256.0

	for( new i = 0 ; i < g_NumTeamPlayers[iTargetTeamID] ; i++ )
	{
		iTargetID = g_SortedTeams[iTargetTeamID][i]
		
		if( !is_user_alive(iTargetID) )
			continue

		else if( iTargetID == iPrevTargets[0] || iTargetID == iPrevTargets[1] || \
					iTargetID == iPrevTargets[2] || iTargetID == iPrevTargets[3] )
			continue

		pev( iTargetID, pev_origin, vTargetOrigin )
		if( get_distance_f( vPrevTargetOrigin, vTargetOrigin) > CHAINHEAL_MAXDISTANCE )
			continue

		pev( iTargetID, pev_view_ofs, view_ofs )
		xs_vec_add( vTargetOrigin, view_ofs, vTargetOrigin )

		engfunc( EngFunc_TraceLine, vTraceStart, vTargetOrigin, IGNORE_MONSTERS|IGNORE_GLASS, FM_NULLENT, hTrace )
		get_tr2( hTrace, TR_flFraction, fFraction )

		if( fFraction < 0.9 )
			continue

		pev( iTargetID, pev_health, fTargetHealth )

		if( fTargetHealth < fBestTargetHealth )
		{
			iBestTarget = iTargetID
			fBestTargetHealth = fTargetHealth
		}
	}

	if( !iBestTarget )
		return

	static vOrigin[3], vPrevOrigin[3]
	get_user_origin( iBestTarget, vOrigin )

	vPrevOrigin[0] = param[8]
	vPrevOrigin[1] = param[9]
	vPrevOrigin[2] = param[10]

	PLAYER_Heal( iBestTarget, iHealth, iCaster )
	Create_TE_ELIGHT( iBestTarget, vOrigin, 100, 128, 255, 0, 10, 0 )
	Create_TE_BEAMENTS( iBestTarget, iPrevTargets[iJump], g_spr_zbeam1, 0, 15, 10, iLineWidth, 4, 128, 255, 0, 128, 10 )
	Create_TE_BEAMENTS( iPrevTargets[iJump], iBestTarget, g_spr_zbeam1, 0, 12, 10, iLineWidth, 6, 128, 128, 128, 128, 0 )
	emit_sound( iBestTarget, CHAN_STATIC, g_szSounds[SOUND_HEAL_LOW_BASE], 0.5, ATTN_NORM, 0, PITCH_NORM )

	if( --iJump < 0 )
		return

	iPrevTargets[iJump] = iBestTarget

	pev( iBestTarget, pev_origin, vTargetOrigin )
	pev( iBestTarget, pev_view_ofs, view_ofs )

	iHealth		= floatround( float(iHealth) * 0.75 )
	iLineWidth	= floatround( float(iLineWidth) * 0.75 )

	param[0]	= iHealth
	param[1]	= iLineWidth
	param[3]	= iJump
	param[4]	= iPrevTargets[0]
	param[5]	= iPrevTargets[1]
	param[6]	= iPrevTargets[2]
	param[7]	= iPrevTargets[3]
	param[8]	= floatround( vTargetOrigin[0] )
	param[9]	= floatround( vTargetOrigin[1] )
	param[10]	= floatround( vTargetOrigin[2] )
	param[11]	= floatround( view_ofs[0] )
	param[12]	= floatround( view_ofs[1] )
	param[13]	= floatround( view_ofs[2] )
	set_task( 0.25, "_SPELL_ChainHealNext", TASK_EFFECT, param, 14 )
}

